/*
 * Copyright 2023-2024, Haiku, Inc. All rights reserved.
 * Distributed under the terms of the MIT License.
 *
 * 龙芯3A6000 LA464微架构原子操作和内存屏障规范
 */
#ifndef _KERNEL_ARCH_LOONGARCH64_ARCH_ATOMIC_H_
#define _KERNEL_ARCH_LOONGARCH64_ARCH_ATOMIC_H_

#include <SupportDefs.h>

#ifdef __cplusplus
extern "C"
{
#endif

    /*
     * 龙芯3A6000 LA464微架构内存屏障使用规范
     *
     * 1. DAMO (Direct Atomic Memory Operation) 指令集
     *    - DAMO指令用于原子内存操作，如原子加、减、交换等
     *    - 在使用DAMO指令前后应插入适当的内存屏障
     *
     * 2. 内存屏障类型
     *    - dbar 0: 完全内存屏障，阻止所有读写重排序
     *    - dbar 1: 写后写屏障，阻止写操作重排序
     *    - dbar 2: 写后读屏障，阻止写操作与后续读操作重排序
     *    - dbar 3: 读后写屏障，阻止读操作与后续写操作重排序
     *    - dbar 4: 读后读屏障，阻止读操作重排序
     *
     * 3. 原子操作内存屏障使用规范
     *    - 在原子操作前使用dbar 0确保之前的内存操作已完成
     *    - 在原子操作后使用dbar 0确保原子操作对其他CPU可见
     *    - 对于读取-修改-写入序列，使用ll/sc指令对，并在前后使用dbar 0
     *
     * 4. 分支预测优化
     *    - 避免在关键路径上使用BEQZ等条件分支指令
     *    - 优先使用条件移动指令(MASKEQZ/MASKNEZ)代替条件分支
     *    - 对于不可避免的分支，使用分支提示指令(JIRL.HINT)
     */

    // 原子操作内存屏障 - 在原子操作前后使用
    static inline void
    atomic_memory_barrier(void)
    {
        __asm__ volatile("dbar 0" ::: "memory");
    }

    // 读内存屏障 - 确保之前的读操作已完成
    static inline void
    atomic_read_barrier(void)
    {
        __asm__ volatile("dbar 4" ::: "memory");
    }

    // 写内存屏障 - 确保之前的写操作已完成
    static inline void
    atomic_write_barrier(void)
    {
        __asm__ volatile("dbar 1" ::: "memory");
    }

    // 读后写内存屏障 - 确保之前的读操作在后续写操作前完成
    static inline void
    atomic_read_write_barrier(void)
    {
        __asm__ volatile("dbar 3" ::: "memory");
    }

    // 写后读内存屏障 - 确保之前的写操作在后续读操作前完成
    static inline void
    atomic_write_read_barrier(void)
    {
        __asm__ volatile("dbar 2" ::: "memory");
    }

    // 原子加操作 - 32位
    static inline int32
    atomic_add(int32 *value, int32 addValue)
    {
        int32 oldValue, newValue;

        atomic_memory_barrier();

        __asm__ volatile(
            "1:\n"
            "\tll.w %0, %3\n"      // 加载链接的字到oldValue
            "\tadd.w %1, %0, %4\n" // 计算新值
            "\tsc.w %1, %3\n"      // 尝试存储新值
            "\tbeqz $a0, 1b\n"     // 如果存储失败，重试
            : "=&r"(oldValue), "=&r"(newValue), "=m"(*value)
            : "m"(*value), "r"(addValue)
            : "memory", "$a0");

        atomic_memory_barrier();

        return oldValue;
    }

    // 原子加操作 - 64位
    static inline int64
    atomic_add64(int64 *value, int64 addValue)
    {
        int64 oldValue, newValue;

        atomic_memory_barrier();

        __asm__ volatile(
            "1:\n"
            "\tll.d %0, %3\n"      // 加载链接的双字到oldValue
            "\tadd.d %1, %0, %4\n" // 计算新值
            "\tsc.d %1, %3\n"      // 尝试存储新值
            "\tbeqz $a0, 1b\n"     // 如果存储失败，重试
            : "=&r"(oldValue), "=&r"(newValue), "=m"(*value)
            : "m"(*value), "r"(addValue)
            : "memory", "$a0");

        atomic_memory_barrier();

        return oldValue;
    }

    // 原子比较和交换 - 32位
    static inline int32
    atomic_test_and_set(int32 *value, int32 setTo, int32 testValue)
    {
        int32 oldValue;

        atomic_memory_barrier();

        __asm__ volatile(
            "1:\n"
            "\tll.w %0, %2\n"    // 加载链接的字到oldValue
            "\tbne %0, %3, 2f\n" // 如果不等于testValue，跳转到2
            "\tsc.w %4, %2\n"    // 尝试存储setTo
            "\tbeqz $a0, 1b\n"   // 如果存储失败，重试
            "2:\n"
            : "=&r"(oldValue), "=m"(*value)
            : "m"(*value), "r"(testValue), "r"(setTo)
            : "memory", "$a0");

        atomic_memory_barrier();

        return oldValue;
    }

    // 原子比较和交换 - 64位
    static inline int64
    atomic_test_and_set64(int64 *value, int64 setTo, int64 testValue)
    {
        int64 oldValue;

        atomic_memory_barrier();

        __asm__ volatile(
            "1:\n"
            "\tll.d %0, %2\n"    // 加载链接的双字到oldValue
            "\tbne %0, %3, 2f\n" // 如果不等于testValue，跳转到2
            "\tsc.d %4, %2\n"    // 尝试存储setTo
            "\tbeqz $a0, 1b\n"   // 如果存储失败，重试
            "2:\n"
            : "=&r"(oldValue), "=m"(*value)
            : "m"(*value), "r"(testValue), "r"(setTo)
            : "memory", "$a0");

        atomic_memory_barrier();

        return oldValue;
    }

    // 使用DAMO指令的原子加操作 - 32位
    // 注意：仅在确认硬件支持DAMO指令时使用
    static inline int32
    atomic_add_damo(int32 *value, int32 addValue)
    {
        int32 oldValue;

        atomic_memory_barrier();

        __asm__ volatile(
            "damo.add.w %0, %2, %1\n" // 原子加操作
            : "=&r"(oldValue), "+m"(*value)
            : "r"(addValue)
            : "memory");

        atomic_memory_barrier();

        return oldValue;
    }

    // 使用DAMO指令的原子加操作 - 64位
    // 注意：仅在确认硬件支持DAMO指令时使用
    static inline int64
    atomic_add64_damo(int64 *value, int64 addValue)
    {
        int64 oldValue;

        atomic_memory_barrier();

        __asm__ volatile(
            "damo.add.d %0, %2, %1\n" // 原子加操作
            : "=&r"(oldValue), "+m"(*value)
            : "r"(addValue)
            : "memory");

        atomic_memory_barrier();

        return oldValue;
    }

#ifdef __cplusplus
}
#endif

#endif /* _KERNEL_ARCH_LOONGARCH64_ARCH_ATOMIC_H_ */